1 EDA using WDI

1.1 Exploratory Data Analysis, EDA

EDA is an iterative cycle that helps you understand what your data says. When you do EDA, you:

  1. Generate questions about your data

  2. Search for answers by visualising, transforming, and/or modeling your data

  3. Use what you learn to refine your questions and/or generate new questions

EDA is an important part of any data analysis. You can use EDA to make discoveries about the world; or you can use EDA to ensure the quality of your data, asking questions about whether the data meets your standards or not. (Posit Primers: EDA)

1.2 Workflow

  1. Importing data by WDI
df_dataframe_name <- WDI(indicators = c(name1 = "Indicator Code 1", 
name2 = "Indicator Code 2"), extra = TRUE)

Write and read:

write_csv(df_dataframe_name, "data/dataframe_name.csv")
df_dataframe_name <- read_csv("data/dataframe_name.csv")
  1. Viewing data by

head(), str(), summary(), and try df_dataframe_name. See also Environment Tab of RStudio.

  1. Transforming data by restricting the values of a variable.
df_dataframe_name |> filter(var == "value") 
df_dataframe_name |> filter(var %in% c("value_1", ... , "value_n") 
df_dataframe_name |> filter(var != "value") 
df_dataframe_name |> distinct(var)
df_dataframe_name |> drop_na(var)
  • Creating a new variable by mutation. (A little advanced. PCAP = gdp/pop)
df_dataframe_name |> mutate(var_new = var1 * var2)}
  1. Change orders by arrange()
df_dataframe_name |> arrange(var)
df_dataframe_name |> arrange(desc(var))
  1. Visualizing using ggplot() + geom_*()

    What type of variation occurs within my variables?

    What type of covariation occurs between my variables?

  • line graph
transformed_data |> ggplot(aes(year, name1)) + geom_line()
transformed_data |> ggplot(aes(year, name2)) + geom_line()
  • scatterplot
transformed_data |> ggplot(aes(name1, name2)) + geom_point()
transformed_data |> ggplot(aes(name1, name2)) + geom_point() + scale_x_log10()
  • scatterplot with a regression line
transformed_data |> ggplot(aes(name1, name2)) + geom_point() +
  geom_smooth(method = "lm", se = FALSE)
transformed_data |> ggplot(aes(name1, name2)) + geom_point() + 
  geom_smooth(method = "lm", se = FALSE) + scale_x_log10()
  • histogram
transformed_data |> ggplot(aes(name1)) + geom_histogram()
  • boxplot

categorical_var: factor(year), income, region

transformed_data |> ggplot(aes(categorical_var, name1)) + geom_boxplot()
  1. Do not forget to add your observations and questions.

1.3 Setup

library(tidyverse)
library(WDI)

1.4 Data

List of data and its description

  1. Government expenditure on education, total (% of GDP): SE.XPD.TOTL.GD.ZS [Link]
  2. School enrollment, primary (% gross): SE.PRM.ENRR [Link]
  3. School enrollment, secondary (% gross): SE.SEC.ENRR [Link]
  4. School enrollment, tertiary (% gross): SE.TER.ENRR [Link]
WDIsearch(string = "SE.XPD.TOTL.GD.ZS", field = "indicator", short = FALSE, cache = wdicache)

1.4.1 Importing Data

df_education <- WDI(
  indicator = c(expenditure = "SE.XPD.TOTL.GD.ZS",
                primary = "SE.PRM.ENRR",
                secondary = "SE.SEC.ENRR",
                tertiary = "SE.TER.ENRR"),
  extra = TRUE, cache = wdicache)
write_csv(df_education, "data/education.csv")
df_education <- read_csv("data/education.csv")
Rows: 16758 Columns: 16── Column specification ───────────────────────────────────────────────────────────
Delimiter: ","
chr  (7): country, iso2c, iso3c, region, capital, income, lending
dbl  (7): year, expenditure, primary, secondary, tertiary, longitude, latitude
lgl  (1): status
date (1): lastupdated
ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.

1.4.2 View Data

head(df_education) or df_education in R Notebook

df_education

Structure of Data: str(df_education) or glimpse(df_education)

str(df_education)
spc_tbl_ [16,758 × 16] (S3: spec_tbl_df/tbl_df/tbl/data.frame)
 $ country    : chr [1:16758] "Afghanistan" "Afghanistan" "Afghanistan" "Afghanistan" ...
 $ iso2c      : chr [1:16758] "AF" "AF" "AF" "AF" ...
 $ iso3c      : chr [1:16758] "AFG" "AFG" "AFG" "AFG" ...
 $ year       : num [1:16758] 2012 2008 2009 2004 2011 ...
 $ status     : logi [1:16758] NA NA NA NA NA NA ...
 $ lastupdated: Date[1:16758], format: "2023-12-18" "2023-12-18" ...
 $ expenditure: num [1:16758] 2.6 4.38 4.81 NA 3.46 ...
 $ primary    : num [1:16758] 106.3 103.4 99.4 106.3 100.3 ...
 $ secondary  : num [1:16758] 54.2 39.1 44.4 19.3 52.2 ...
 $ tertiary   : num [1:16758] NA NA 4.02 1.39 3.76 ...
 $ region     : chr [1:16758] "South Asia" "South Asia" "South Asia" "South Asia" ...
 $ capital    : chr [1:16758] "Kabul" "Kabul" "Kabul" "Kabul" ...
 $ longitude  : num [1:16758] 69.2 69.2 69.2 69.2 69.2 ...
 $ latitude   : num [1:16758] 34.5 34.5 34.5 34.5 34.5 ...
 $ income     : chr [1:16758] "Low income" "Low income" "Low income" "Low income" ...
 $ lending    : chr [1:16758] "IDA" "IDA" "IDA" "IDA" ...
 - attr(*, "spec")=
  .. cols(
  ..   country = col_character(),
  ..   iso2c = col_character(),
  ..   iso3c = col_character(),
  ..   year = col_double(),
  ..   status = col_logical(),
  ..   lastupdated = col_date(format = ""),
  ..   expenditure = col_double(),
  ..   primary = col_double(),
  ..   secondary = col_double(),
  ..   tertiary = col_double(),
  ..   region = col_character(),
  ..   capital = col_character(),
  ..   longitude = col_double(),
  ..   latitude = col_double(),
  ..   income = col_character(),
  ..   lending = col_character()
  .. )
 - attr(*, "problems")=<externalptr> 

1.4.3 Select Columns

df_ed <- df_education |> select(country, iso2c, year, expenditure, primary, secondary, tertiary, region, income, lending)
df_ed
df_ed |> filter(region == "Aggregates") |> distinct(country)

1.4.3.1 Check Data

df_ed |> group_by(year) |> summarize(expenditure = sum(!is.na(expenditure)), 
                                     primary = sum(!is.na(primary)),
                                     secondary = sum(!is.na(secondary)),
                                     tertiary = sum(!is.na(tertiary))) |>
  arrange(desc(year))

1.4.4 Visualization by Line Graphs

1.4.4.1 Government expenditure on education, total (% of GDP)

df_ed |> filter(country == "Sub-Saharan Africa") |> drop_na(expenditure) |>
  ggplot(aes(year, expenditure)) + geom_line()

df_ed |> filter(region == "Sub-Saharan Africa") |>
  group_by(year) |> summarize(expenditure = sum(!is.na(expenditure)), 
                                     primary = sum(!is.na(primary)),
                                     secondary = sum(!is.na(secondary)),
                                     tertiary = sum(!is.na(tertiary))) |>
  arrange(desc(year))
df_ed |> drop_na(expenditure) |> filter(country %in% c("Arab World", "Africa Eastern and Southern", "Africa Western and Central", "Sub-Saharan Africa", "South Asia")) |> 
  ggplot(aes(year, expenditure, col = country)) + geom_line()

df_ed |> filter(country == "Sub-Saharan Africa") |> drop_na(expenditure) |>
  ggplot(aes(year, primary)) + geom_line()

df_ed |> filter(country == "Sub-Saharan Africa") |> drop_na(primary) |>
  ggplot() + geom_line(aes(year, primary), col = "red") + geom_line(aes(year, secondary), col = "blue") + geom_line(aes(year, tertiary)) + labs(title = "School Enrollment", y = "% gross")

1.4.5 Long Table

df |> pivot_longer(cols = c(columns to gather), names_to = "name", values_to = "value")

primary:tertiary from the column primary to the column tertiary

df_ed_long <- df_ed |> pivot_longer(cols = primary:tertiary, names_to = "levels", values_to = "value") 
df_ed_long

1.4.5.1 Examples

Purchasing power parities (PPPs): [R Notebook], [Rmd]

df_gdps_long <- df_gdps |> 
  pivot_longer(cols = c("gdp_nominal", "gdp_real", "gdp_ppp"),
               names_to = "gdp", values_to = "value")
df_ed_long |> drop_na(value) |> 
  filter(country == "Sub-Saharan Africa") |>
  ggplot(aes(year, value, col = levels)) + geom_line()

df_ed_long |> drop_na(value) |> 
  filter(country %in% c("Sub-Saharan Africa", "South Asia")) |>
  ggplot(aes(year, value, col = country, linetype = levels)) + geom_line()

2 Example

2.1 School Enrollment vs GDP Per Capita

We study the relation between the school enrollment in secondary and tertiary level and the gdp per capita.

2.1.2 Importing Data

df_sec_ter_gdp <- WDI(
  indicator = c(secondary = "SE.SEC.ENRR", tertiary = "SE.TER.ENRR", 
                gdppcap = "NY.GDP.PCAP.PP.KD"), 
  extra = TRUE, cache = wdicache)
write_csv(df_sec_ter_gdp, "data/sec_ter_gdp.csv")
df_df_sec_ter_gdp <- read_csv("data/sec_ter_gdp.csv")
Rows: 16758 Columns: 15── Column specification ───────────────────────────────────────────────────────────
Delimiter: ","
chr  (7): country, iso2c, iso3c, region, capital, income, lending
dbl  (6): year, secondary, tertiary, gdppcap, longitude, latitude
lgl  (1): status
date (1): lastupdated
ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.

2.1.3 Viewing the data

df_sec_ter_gdp
df_sec_ter_gdp |> str()
'data.frame':   16758 obs. of  15 variables:
 $ country    : chr  "Afghanistan" "Afghanistan" "Afghanistan" "Afghanistan" ...
 $ iso2c      : chr  "AF" "AF" "AF" "AF" ...
 $ iso3c      : chr  "AFG" "AFG" "AFG" "AFG" ...
 $ year       : int  2012 2008 2009 2004 2011 2013 2014 2010 2003 2007 ...
 $ status     : chr  "" "" "" "" ...
 $ lastupdated: chr  "2023-12-18" "2023-12-18" "2023-12-18" "2023-12-18" ...
 $ secondary  : num  54.2 39.1 44.4 19.3 52.2 ...
  ..- attr(*, "label")= chr "School enrollment, secondary (% gross)"
 $ tertiary   : num  NA NA 4.02 1.39 3.76 ...
  ..- attr(*, "label")= chr "School enrollment, tertiary (% gross)"
 $ gdppcap    : num  2123 1557 1824 1260 1961 ...
  ..- attr(*, "label")= chr "GDP per capita, PPP (constant 2017 international $)"
 $ region     : chr  "South Asia" "South Asia" "South Asia" "South Asia" ...
 $ capital    : chr  "Kabul" "Kabul" "Kabul" "Kabul" ...
 $ longitude  : chr  "69.1761" "69.1761" "69.1761" "69.1761" ...
 $ latitude   : chr  "34.5228" "34.5228" "34.5228" "34.5228" ...
 $ income     : chr  "Low income" "Low income" "Low income" "Low income" ...
 $ lending    : chr  "IDA" "IDA" "IDA" "IDA" ...

2.1.4 Creating a Long Table

df_sec_ter_gdp_long <- df_sec_ter_gdp |> 
  pivot_longer(cols = c(secondary, tertiary)) |>
  select(country, iso2c, year, gdppcap, name, value, region, income)
df_sec_ter_gdp_long

2.1.5 Visualizing by Line Graphs

COUNTRY <- "World"
df_sec_ter_gdp_long |> filter(country == COUNTRY) |> drop_na(value) |>
  ggplot() + geom_line(aes(year, value, col = name))

  labs(title = "School enrollment; Secondary and Tertiary")
$title
[1] "School enrollment; Secondary and Tertiary"

attr(,"class")
[1] "labels"

Observations:

  • The enrollments of both levels are increasing rapidly after 1990.
INCOME <- c("High income", "Upper middle income","Middle income","Lower middle income","Low & middle income", "Low income")
df_sec_ter_gdp_long |> filter(country %in% INCOME) |> drop_na(value) |>
  ggplot(aes(year, value, col = factor(country, levels = INCOME), linetype = name)) + geom_line() + ylim(c(0,110)) +
  labs(title = "School enrollment: Secondary and Tertiary", 
       col = "Incom Levels",
       linetype = "School Levels", y = "")

Observations

  • In this century, we can observe improvements in enrollments. Need to study more in detail.

2.1.6 Scatterplots for Covariation

df_sec_ter_gdp_long |> filter(year == 2020) |> drop_na(value, gdppcap) |>
  ggplot(aes(gdppcap, value, col = name)) + geom_point() + 
  labs(title = "School enrollment: Secondary and Tertiary vs GDP per capita", y = "")

Observations

  • Need to try log10 convertion of gdppcap as many points are near the origin.
df_sec_ter_gdp_long |> filter(year == 2020) |> drop_na(value, gdppcap) |>
  ggplot(aes(gdppcap, value, col = name)) + geom_point() + 
  scale_x_log10() +
  labs(title = "School enrollment; Secondary and Tertiary vs GDP per capita in log10 scale", y = "")

df_sec_ter_gdp_long |> filter(year == 2020) |> drop_na(value, gdppcap) |>
  ggplot(aes(gdppcap, value, col = name)) + geom_point() + 
  geom_smooth(method = "lm", se = FALSE, formula = 'y~x') +
  scale_x_log10() +
  labs(title = "School enrollment; Secondary and Tertiary vs GDP per capita in log10 scale", y = "")

df_sec_ter_gdp_long |> filter(year == 2020) |> drop_na(gdppcap, value) |>
  filter(name == "tertiary") |> 
  lm(value~log10(gdppcap), data = _) |> summary()

Call:
lm(formula = value ~ log10(gdppcap), data = filter(drop_na(filter(df_sec_ter_gdp_long, 
    year == 2020), gdppcap, value), name == "tertiary"))

Residuals:
    Min      1Q  Median      3Q     Max 
-70.323  -8.289  -0.605   8.209  83.181 

Coefficients:
               Estimate Std. Error t value Pr(>|t|)    
(Intercept)    -155.838     12.831  -12.14   <2e-16 ***
log10(gdppcap)   48.735      3.064   15.90   <2e-16 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 18.36 on 170 degrees of freedom
Multiple R-squared:  0.598, Adjusted R-squared:  0.5957 
F-statistic: 252.9 on 1 and 170 DF,  p-value: < 2.2e-16

Observations

  • Both secondary and tertiary level, the enrollment correlate with the log10 values of gdp per capita.

2.1.7 Box Plots

df_sec_ter_gdp_long |> filter(year == 2020, region != "Aggregates") |> drop_na(value, region) |>
  ggplot(aes(name, value, fill = region)) + geom_boxplot() + 
  labs(title = "Secondary and tertiary school enrollment by region", y = "School enrollment (% gross)", x = "", fill = "") + 
  theme(legend.position = "top")

Observations

  • Regional differences are large in tertiary level.
df_sec_ter_gdp_long |> filter(year == 2020, region != "Aggregates") |> drop_na(value, income) |>
  ggplot(aes(name, value, fill = factor(income, levels = INCOME))) + geom_boxplot() + 
  labs(title = "Secondary and tertiary school enrollment by income level", y = "School enrollment (% gross)", x = "", fill = "") + 
  theme(legend.position = "top")

Observations

  • Income level has more effect on school enrollment to both secondary and tertiary education

3 Your Project

3.1 Title of your project

The title can be in the title in YAML.

3.1.1 Short Abstract

We study …..

3.1.2 About Data

  1. Name of the indicator 1: Indicator Code 1
  • Description:
  1. Name of the indicator 2: Indicator Code 2
  • Description:

3.1.3 Set up

library(tidyverse)
library(WDI)

Create data folder if you do not have it under Files.

dir.create("data")

If you do not have wdicache.rds in your data folder, run the following two code chunks.

wdicache <- WDIcache()

3.1.4 Importing Data

Edit short_name_1, chosen_indicator_1, short_name_2, chosen_indicator_2, etc. You can edit df_yourdata to a descriptive name. If you edit df_yourdata , please edit other parts as well.

df_yourdata <- WDI(
  indicator = c(short_name_1 = chosen_indicator_1,
                short_name_2 = chosen_indicator_2),
  extra = TRUE, cache = wdicache)
write_csv(df_yourdata, "data/yourdata.csv")
df_yourdata <- read_csv("data/yourdata.csv")

3.1.5 Viewing data

3.1.6 Creating a long table

3.1.6.1 Example.

df_sec_ter_gdp_long <- df_sec_ter_gdp |> 
  pivot_longer(cols = c(secondary, tertiary)) 
df_sec_ter_gdp_long

3.1.7 Visualizing data

Observations and Questions:

Observations and Questions:

Observations and Questions:

3.1.8 A choropleth map

If possible, create a choropleth map. (a challenge, not required)

Observations and Questions:

LS0tCnRpdGxlOiAiRWR1Y2F0aW9uIgphdXRob3I6ICJJRCBMYXN0LCBGaXJzdCIKZGF0ZTogImByIFN5cy5EYXRlKClgIgpvdXRwdXQ6CiAgaHRtbF9ub3RlYm9vazoKICAgIG51bWJlcl9zZWN0aW9uczogeWVzCiAgICB0b2M6IHllcwogICAgdG9jX2Zsb2F0OiB5ZXMKLS0tCgojIEVEQSB1c2luZyBXREkKCiMjIEV4cGxvcmF0b3J5IERhdGEgQW5hbHlzaXMsIEVEQQoKRURBIGlzIGFuIGl0ZXJhdGl2ZSBjeWNsZSB0aGF0IGhlbHBzIHlvdSB1bmRlcnN0YW5kIHdoYXQgeW91ciBkYXRhIHNheXMuIFdoZW4geW91IGRvIEVEQSwgeW91OgoKMS4gIEdlbmVyYXRlIHF1ZXN0aW9ucyBhYm91dCB5b3VyIGRhdGEKCjIuICBTZWFyY2ggZm9yIGFuc3dlcnMgYnkgdmlzdWFsaXNpbmcsIHRyYW5zZm9ybWluZywgYW5kL29yIG1vZGVsaW5nIHlvdXIgZGF0YQoKMy4gIFVzZSB3aGF0IHlvdSBsZWFybiB0byByZWZpbmUgeW91ciBxdWVzdGlvbnMgYW5kL29yIGdlbmVyYXRlIG5ldyBxdWVzdGlvbnMKCkVEQSBpcyBhbiBpbXBvcnRhbnQgcGFydCBvZiBhbnkgZGF0YSBhbmFseXNpcy4gWW91IGNhbiB1c2UgRURBIHRvIG1ha2UgZGlzY292ZXJpZXMgYWJvdXQgdGhlIHdvcmxkOyBvciB5b3UgY2FuIHVzZSBFREEgdG8gZW5zdXJlIHRoZSBxdWFsaXR5IG9mIHlvdXIgZGF0YSwgYXNraW5nIHF1ZXN0aW9ucyBhYm91dCB3aGV0aGVyIHRoZSBkYXRhIG1lZXRzIHlvdXIgc3RhbmRhcmRzIG9yIG5vdC4gKFBvc2l0IFByaW1lcnM6IFtFREFdKGh0dHBzOi8vcG9zaXQuY2xvdWQvbGVhcm4vcHJpbWVycy8zLjEpKQoKIyMgV29ya2Zsb3cKCjEuICBJbXBvcnRpbmcgZGF0YSBieSBXREkKCmBgYCAgICAgICAgIApkZl9kYXRhZnJhbWVfbmFtZSA8LSBXREkoaW5kaWNhdG9ycyA9IGMobmFtZTEgPSAiSW5kaWNhdG9yIENvZGUgMSIsIApuYW1lMiA9ICJJbmRpY2F0b3IgQ29kZSAyIiksIGV4dHJhID0gVFJVRSkKYGBgCgpXcml0ZSBhbmQgcmVhZDoKCmBgYCAgICAgICAgIAp3cml0ZV9jc3YoZGZfZGF0YWZyYW1lX25hbWUsICJkYXRhL2RhdGFmcmFtZV9uYW1lLmNzdiIpCmRmX2RhdGFmcmFtZV9uYW1lIDwtIHJlYWRfY3N2KCJkYXRhL2RhdGFmcmFtZV9uYW1lLmNzdiIpCmBgYAoKMi4gIFZpZXdpbmcgZGF0YSBieQoKYGhlYWQoKWAsIGBzdHIoKWAsIGBzdW1tYXJ5KClgLCBhbmQgdHJ5IGBkZl9kYXRhZnJhbWVfbmFtZWAuIFNlZSBhbHNvIEVudmlyb25tZW50IFRhYiBvZiBSU3R1ZGlvLgoKMy4gIFRyYW5zZm9ybWluZyBkYXRhIGJ5IHJlc3RyaWN0aW5nIHRoZSB2YWx1ZXMgb2YgYSB2YXJpYWJsZS4KCmBgYCAgICAgICAgIApkZl9kYXRhZnJhbWVfbmFtZSB8PiBmaWx0ZXIodmFyID09ICJ2YWx1ZSIpIApkZl9kYXRhZnJhbWVfbmFtZSB8PiBmaWx0ZXIodmFyICVpbiUgYygidmFsdWVfMSIsIC4uLiAsICJ2YWx1ZV9uIikgCmRmX2RhdGFmcmFtZV9uYW1lIHw+IGZpbHRlcih2YXIgIT0gInZhbHVlIikgCmRmX2RhdGFmcmFtZV9uYW1lIHw+IGRpc3RpbmN0KHZhcikKZGZfZGF0YWZyYW1lX25hbWUgfD4gZHJvcF9uYSh2YXIpCmBgYAoKLSAgIENyZWF0aW5nIGEgbmV3IHZhcmlhYmxlIGJ5IG11dGF0aW9uLiAoQSBsaXR0bGUgYWR2YW5jZWQuIFBDQVAgPSBnZHAvcG9wKQoKYGBgICAgICAgICAgCmRmX2RhdGFmcmFtZV9uYW1lIHw+IG11dGF0ZSh2YXJfbmV3ID0gdmFyMSAqIHZhcjIpfQpgYGAKCjQuICBDaGFuZ2Ugb3JkZXJzIGJ5IGBhcnJhbmdlKClgCgpgYGAgICAgICAgICAKZGZfZGF0YWZyYW1lX25hbWUgfD4gYXJyYW5nZSh2YXIpCmRmX2RhdGFmcmFtZV9uYW1lIHw+IGFycmFuZ2UoZGVzYyh2YXIpKQpgYGAKCjUuICBWaXN1YWxpemluZyB1c2luZyBnZ3Bsb3QoKSArIGdlb21cX1wqKCkKCiAgICBXaGF0IHR5cGUgb2bCoCoqdmFyaWF0aW9uKirCoG9jY3Vyc8KgKip3aXRoaW4qKsKgbXkgdmFyaWFibGVzPwoKICAgIFdoYXQgdHlwZSBvZsKgKipjb3ZhcmlhdGlvbioqwqBvY2N1cnPCoCoqYmV0d2VlbioqwqBteSB2YXJpYWJsZXM/CgotICAgbGluZSBncmFwaAoKYGBgICAgICAgICAgCnRyYW5zZm9ybWVkX2RhdGEgfD4gZ2dwbG90KGFlcyh5ZWFyLCBuYW1lMSkpICsgZ2VvbV9saW5lKCkKdHJhbnNmb3JtZWRfZGF0YSB8PiBnZ3Bsb3QoYWVzKHllYXIsIG5hbWUyKSkgKyBnZW9tX2xpbmUoKQpgYGAKCi0gICBzY2F0dGVycGxvdAoKYGBgICAgICAgICAgCnRyYW5zZm9ybWVkX2RhdGEgfD4gZ2dwbG90KGFlcyhuYW1lMSwgbmFtZTIpKSArIGdlb21fcG9pbnQoKQp0cmFuc2Zvcm1lZF9kYXRhIHw+IGdncGxvdChhZXMobmFtZTEsIG5hbWUyKSkgKyBnZW9tX3BvaW50KCkgKyBzY2FsZV94X2xvZzEwKCkKYGBgCgotICAgc2NhdHRlcnBsb3Qgd2l0aCBhIHJlZ3Jlc3Npb24gbGluZQoKYGBgICAgICAgICAgCnRyYW5zZm9ybWVkX2RhdGEgfD4gZ2dwbG90KGFlcyhuYW1lMSwgbmFtZTIpKSArIGdlb21fcG9pbnQoKSArCiAgZ2VvbV9zbW9vdGgobWV0aG9kID0gImxtIiwgc2UgPSBGQUxTRSkKdHJhbnNmb3JtZWRfZGF0YSB8PiBnZ3Bsb3QoYWVzKG5hbWUxLCBuYW1lMikpICsgZ2VvbV9wb2ludCgpICsgCiAgZ2VvbV9zbW9vdGgobWV0aG9kID0gImxtIiwgc2UgPSBGQUxTRSkgKyBzY2FsZV94X2xvZzEwKCkKYGBgCgotICAgaGlzdG9ncmFtCgpgYGAgICAgICAgICAKdHJhbnNmb3JtZWRfZGF0YSB8PiBnZ3Bsb3QoYWVzKG5hbWUxKSkgKyBnZW9tX2hpc3RvZ3JhbSgpCmBgYAoKLSAgIGJveHBsb3QKCmBjYXRlZ29yaWNhbF92YXJgOiBgZmFjdG9yKHllYXIpYCwgYGluY29tZWAsIGByZWdpb25gCgpgYGAgICAgICAgICAKdHJhbnNmb3JtZWRfZGF0YSB8PiBnZ3Bsb3QoYWVzKGNhdGVnb3JpY2FsX3ZhciwgbmFtZTEpKSArIGdlb21fYm94cGxvdCgpCmBgYAoKNi4gIERvIG5vdCBmb3JnZXQgdG8gYWRkIHlvdXIgb2JzZXJ2YXRpb25zIGFuZCBxdWVzdGlvbnMuCgojIyBTZXR1cAoKYGBge3J9CmxpYnJhcnkodGlkeXZlcnNlKQpsaWJyYXJ5KFdESSkKYGBgCgojIyMgV0RJY2FjaGUoKSBbW0xpbmsgaW4gZGE0cl0oaHR0cHM6Ly9pY3UtaHN1enVraS5naXRodWIuaW8vZGE0ci93ZGlkYXRhLmh0bWw/cT1XREljYWNoZSN3ZGljYWNoZSldCgpJZiB5b3UgaGF2ZSBub3QgZG93bmxvYWQgV0RJY2FjaGUgcmVjZW50bHksIHJ1biB0aGUgZm9sbG93aW5nIHR3byBjb2RlIGNodW5rcywgb3RoZXJ3aXNlIHN0YXJ0IHdpdGggdGhlIHRoaXJkLgoKYGBge3IgZXZhbD1GQUxTRX0Kd2RpY2FjaGUgPC0gV0RJY2FjaGUoKQpgYGAKCmBgYHtyIGV2YWw9RkFMU0V9CndyaXRlX3Jkcyh3ZGljYWNoZSwgImRhdGEvd2RpY2FjaGUucmRzIikKYGBgCgpgYGB7ciBldmFsPVRSVUV9CndkaWNhY2hlIDwtIHJlYWRfcmRzKCJkYXRhL3dkaWNhY2hlLnJkcyIpCmBgYAoKIyMgRGF0YQoKKkxpc3Qgb2YgZGF0YSBhbmQgaXRzIGRlc2NyaXB0aW9uKgoKMS4gIEdvdmVybm1lbnQgZXhwZW5kaXR1cmUgb24gZWR1Y2F0aW9uLCB0b3RhbCAoJSBvZiBHRFApOiBTRS5YUEQuVE9UTC5HRC5aUyBbW0xpbmtdKGh0dHBzOi8vZGF0YS53b3JsZGJhbmsub3JnL2luZGljYXRvci9TRS5YUEQuVE9UTC5HRC5aUyldCjIuICBTY2hvb2wgZW5yb2xsbWVudCwgcHJpbWFyeSAoJSBncm9zcyk6IFNFLlBSTS5FTlJSIFtbTGlua10oaHR0cHM6Ly9kYXRhLndvcmxkYmFuay5vcmcvaW5kaWNhdG9yL1NFLlBSTS5FTlJSKV0KMy4gIFNjaG9vbCBlbnJvbGxtZW50LCBzZWNvbmRhcnkgKCUgZ3Jvc3MpOiBTRS5TRUMuRU5SUiBbW0xpbmtdKGh0dHBzOi8vZGF0YS53b3JsZGJhbmsub3JnL2luZGljYXRvci9TRS5TRUMuRU5SUildCjQuICBTY2hvb2wgZW5yb2xsbWVudCwgdGVydGlhcnkgKCUgZ3Jvc3MpOiBTRS5URVIuRU5SUiBbW0xpbmtdKGh0dHBzOi8vZGF0YS53b3JsZGJhbmsub3JnL2luZGljYXRvci9TRS5URVIuRU5SUildCgpgYGB7cn0KV0RJc2VhcmNoKHN0cmluZyA9ICJTRS5YUEQuVE9UTC5HRC5aUyIsIGZpZWxkID0gImluZGljYXRvciIsIHNob3J0ID0gRkFMU0UsIGNhY2hlID0gd2RpY2FjaGUpCmBgYAoKIyMjIEltcG9ydGluZyBEYXRhCgpgYGB7ciBjYWNoZSA9IFRSVUUsIGV2YWwgPSBGQUxTRX0KZGZfZWR1Y2F0aW9uIDwtIFdESSgKICBpbmRpY2F0b3IgPSBjKGV4cGVuZGl0dXJlID0gIlNFLlhQRC5UT1RMLkdELlpTIiwKICAgICAgICAgICAgICAgIHByaW1hcnkgPSAiU0UuUFJNLkVOUlIiLAogICAgICAgICAgICAgICAgc2Vjb25kYXJ5ID0gIlNFLlNFQy5FTlJSIiwKICAgICAgICAgICAgICAgIHRlcnRpYXJ5ID0gIlNFLlRFUi5FTlJSIiksCiAgZXh0cmEgPSBUUlVFLCBjYWNoZSA9IHdkaWNhY2hlKQpgYGAKCmBgYHtyIGV2YWwgPSBGQUxTRX0Kd3JpdGVfY3N2KGRmX2VkdWNhdGlvbiwgImRhdGEvZWR1Y2F0aW9uLmNzdiIpCmBgYAoKYGBge3J9CmRmX2VkdWNhdGlvbiA8LSByZWFkX2NzdigiZGF0YS9lZHVjYXRpb24uY3N2IikKYGBgCgojIyMgVmlldyBEYXRhCgpgaGVhZChkZl9lZHVjYXRpb24pYCBvciBgZGZfZWR1Y2F0aW9uYCBpbiBSIE5vdGVib29rCgpgYGB7cn0KZGZfZWR1Y2F0aW9uCmBgYAoKU3RydWN0dXJlIG9mIERhdGE6IGBzdHIoZGZfZWR1Y2F0aW9uKWAgb3IgYGdsaW1wc2UoZGZfZWR1Y2F0aW9uKWAKCmBgYHtyfQpzdHIoZGZfZWR1Y2F0aW9uKQpgYGAKCiMjIyBTZWxlY3QgQ29sdW1ucwoKYGBge3J9CmRmX2VkIDwtIGRmX2VkdWNhdGlvbiB8PiBzZWxlY3QoY291bnRyeSwgaXNvMmMsIHllYXIsIGV4cGVuZGl0dXJlLCBwcmltYXJ5LCBzZWNvbmRhcnksIHRlcnRpYXJ5LCByZWdpb24sIGluY29tZSwgbGVuZGluZykKZGZfZWQKYGBgCgpgYGB7cn0KZGZfZWQgfD4gZmlsdGVyKHJlZ2lvbiA9PSAiQWdncmVnYXRlcyIpIHw+IGRpc3RpbmN0KGNvdW50cnkpCmBgYAoKIyMjIyBDaGVjayBEYXRhCgpgYGB7cn0KZGZfZWQgfD4gZ3JvdXBfYnkoeWVhcikgfD4gc3VtbWFyaXplKGV4cGVuZGl0dXJlID0gc3VtKCFpcy5uYShleHBlbmRpdHVyZSkpLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHByaW1hcnkgPSBzdW0oIWlzLm5hKHByaW1hcnkpKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNlY29uZGFyeSA9IHN1bSghaXMubmEoc2Vjb25kYXJ5KSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0ZXJ0aWFyeSA9IHN1bSghaXMubmEodGVydGlhcnkpKSkgfD4KICBhcnJhbmdlKGRlc2MoeWVhcikpCmBgYAoKIyMjIFZpc3VhbGl6YXRpb24gYnkgTGluZSBHcmFwaHMKCiMjIyMgR292ZXJubWVudCBleHBlbmRpdHVyZSBvbiBlZHVjYXRpb24sIHRvdGFsICglIG9mIEdEUCkKCmBgYHtyfQpkZl9lZCB8PiBmaWx0ZXIoY291bnRyeSA9PSAiU3ViLVNhaGFyYW4gQWZyaWNhIikgfD4gZHJvcF9uYShleHBlbmRpdHVyZSkgfD4KICBnZ3Bsb3QoYWVzKHllYXIsIGV4cGVuZGl0dXJlKSkgKyBnZW9tX2xpbmUoKQpgYGAKCmBgYHtyfQpkZl9lZCB8PiBmaWx0ZXIocmVnaW9uID09ICJTdWItU2FoYXJhbiBBZnJpY2EiKSB8PgogIGdyb3VwX2J5KHllYXIpIHw+IHN1bW1hcml6ZShleHBlbmRpdHVyZSA9IHN1bSghaXMubmEoZXhwZW5kaXR1cmUpKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwcmltYXJ5ID0gc3VtKCFpcy5uYShwcmltYXJ5KSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzZWNvbmRhcnkgPSBzdW0oIWlzLm5hKHNlY29uZGFyeSkpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGVydGlhcnkgPSBzdW0oIWlzLm5hKHRlcnRpYXJ5KSkpIHw+CiAgYXJyYW5nZShkZXNjKHllYXIpKQpgYGAKCmBgYHtyfQpkZl9lZCB8PiBkcm9wX25hKGV4cGVuZGl0dXJlKSB8PiBmaWx0ZXIoY291bnRyeSAlaW4lIGMoIkFyYWIgV29ybGQiLCAiQWZyaWNhIEVhc3Rlcm4gYW5kIFNvdXRoZXJuIiwgIkFmcmljYSBXZXN0ZXJuIGFuZCBDZW50cmFsIiwgIlN1Yi1TYWhhcmFuIEFmcmljYSIsICJTb3V0aCBBc2lhIikpIHw+IAogIGdncGxvdChhZXMoeWVhciwgZXhwZW5kaXR1cmUsIGNvbCA9IGNvdW50cnkpKSArIGdlb21fbGluZSgpCmBgYAoKYGBge3J9CmRmX2VkIHw+IGZpbHRlcihjb3VudHJ5ID09ICJTdWItU2FoYXJhbiBBZnJpY2EiKSB8PiBkcm9wX25hKGV4cGVuZGl0dXJlKSB8PgogIGdncGxvdChhZXMoeWVhciwgcHJpbWFyeSkpICsgZ2VvbV9saW5lKCkKYGBgCgpgYGB7cn0KZGZfZWQgfD4gZmlsdGVyKGNvdW50cnkgPT0gIlN1Yi1TYWhhcmFuIEFmcmljYSIpIHw+IGRyb3BfbmEocHJpbWFyeSkgfD4KICBnZ3Bsb3QoKSArIGdlb21fbGluZShhZXMoeWVhciwgcHJpbWFyeSksIGNvbCA9ICJyZWQiKSArIGdlb21fbGluZShhZXMoeWVhciwgc2Vjb25kYXJ5KSwgY29sID0gImJsdWUiKSArIGdlb21fbGluZShhZXMoeWVhciwgdGVydGlhcnkpKSArIGxhYnModGl0bGUgPSAiU2Nob29sIEVucm9sbG1lbnQiLCB5ID0gIiUgZ3Jvc3MiKQpgYGAKCiMjIyBMb25nIFRhYmxlCgpgYGAgICAgICAgICAKZGYgfD4gcGl2b3RfbG9uZ2VyKGNvbHMgPSBjKGNvbHVtbnMgdG8gZ2F0aGVyKSwgbmFtZXNfdG8gPSAibmFtZSIsIHZhbHVlc190byA9ICJ2YWx1ZSIpCmBgYAoKYHByaW1hcnk6dGVydGlhcnlgIGZyb20gdGhlIGNvbHVtbiBwcmltYXJ5IHRvIHRoZSBjb2x1bW4gdGVydGlhcnkKCmBgYHtyfQpkZl9lZF9sb25nIDwtIGRmX2VkIHw+IHBpdm90X2xvbmdlcihjb2xzID0gcHJpbWFyeTp0ZXJ0aWFyeSwgbmFtZXNfdG8gPSAibGV2ZWxzIiwgdmFsdWVzX3RvID0gInZhbHVlIikgCmRmX2VkX2xvbmcKYGBgCgojIyMjIEV4YW1wbGVzCgpQdXJjaGFzaW5nIHBvd2VyIHBhcml0aWVzIChQUFBzKTogW1tSIE5vdGVib29rXShodHRwczovL2RzLXNsLmdpdGh1Yi5pby9pbnRybzJyL2RhNHIvZ2RwX3BwcC5uYi5odG1sKV0sIFtbUm1kXShodHRwczovL2dpdGh1Yi5jb20vZHMtc2wvaW50cm8yci9ibG9iL21haW4vZG9jcy9kYTRyL2dkcF9wcHAuUm1kKV0KCmBgYCAgICAgICAgIApkZl9nZHBzX2xvbmcgPC0gZGZfZ2RwcyB8PiAKICBwaXZvdF9sb25nZXIoY29scyA9IGMoImdkcF9ub21pbmFsIiwgImdkcF9yZWFsIiwgImdkcF9wcHAiKSwKICAgICAgICAgICAgICAgbmFtZXNfdG8gPSAiZ2RwIiwgdmFsdWVzX3RvID0gInZhbHVlIikKYGBgCgpgYGB7cn0KZGZfZWRfbG9uZyB8PiBkcm9wX25hKHZhbHVlKSB8PiAKICBmaWx0ZXIoY291bnRyeSA9PSAiU3ViLVNhaGFyYW4gQWZyaWNhIikgfD4KICBnZ3Bsb3QoYWVzKHllYXIsIHZhbHVlLCBjb2wgPSBsZXZlbHMpKSArIGdlb21fbGluZSgpCmBgYAoKYGBge3J9CmRmX2VkX2xvbmcgfD4gZHJvcF9uYSh2YWx1ZSkgfD4gCiAgZmlsdGVyKGNvdW50cnkgJWluJSBjKCJTdWItU2FoYXJhbiBBZnJpY2EiLCAiU291dGggQXNpYSIpKSB8PgogIGdncGxvdChhZXMoeWVhciwgdmFsdWUsIGNvbCA9IGNvdW50cnksIGxpbmV0eXBlID0gbGV2ZWxzKSkgKyBnZW9tX2xpbmUoKQpgYGAKCiMjIENob3JvcGxldGggTWFwcyBbW0xpbmtdKGh0dHBzOi8vaWN1LWhzdXp1a2kuZ2l0aHViLmlvL2RhNHIvd29ybGRtYXAuaHRtbCN3b3JsZG1hcCldCgpOZWVkIG1hcCBkYXRhIGFuZCB1c2UgYGdlb21fc2ZgCgojIyMgKipOYXR1cmFsIEVhcnRoIERhdGEqKgoKW2h0dHBzOi8vd3d3Lm5hdHVyYWxlYXJ0aGRhdGEuY29tXShodHRwczovL3d3dy5uYXR1cmFsZWFydGhkYXRhLmNvbS8pCgpHZXQgbmF0dXJhbCBlYXJ0aCB3b3JsZCBjb3VudHJ5IHBvbHlnb25zCgpDUkFOOiA8aHR0cHM6Ly9jcmFuLnItcHJvamVjdC5vcmcvd2ViL3BhY2thZ2VzL3JuYXR1cmFsZWFydGgvaW5kZXguaHRtbD4KCk1hbnVhbDrCoDxodHRwczovL2NyYW4uci1wcm9qZWN0Lm9yZy93ZWIvcGFja2FnZXMvcm5hdHVyYWxlYXJ0aC9ybmF0dXJhbGVhcnRoLnBkZj4KCmBgYHtyfQpsaWJyYXJ5KHJuYXR1cmFsZWFydGgpCmxpYnJhcnkocm5hdHVyYWxlYXJ0aGRhdGEpCmBgYAoKYGBgICAgICAgICAgCm5lX2NvdW50cmllcygKICBzY2FsZSA9IDExMCwKICB0eXBlID0gImNvdW50cmllcyIsCiAgY29udGluZW50ID0gTlVMTCwKICBjb3VudHJ5ID0gTlVMTCwKICBnZW91bml0ID0gTlVMTCwKICBzb3ZlcmVpZ250eSA9IE5VTEwsCiAgcmV0dXJuY2xhc3MgPSBjKCJzcCIsICJzZiIpCikKYGBgCgojIyMjICoqQXJndW1lbnRzKioKCi0gICBzY2FsZTogc2NhbGUgb2YgbWFwIHRvIHJldHVybiwgb25lIG9mIDExMCwgNTAsIDEwIG9yIOKAmHNtYWxs4oCZLCDigJhtZWRpdW3igJksIOKAmGxhcmdl4oCZCgotICAgdHlwZTogY291bnRyeSB0eXBlLCBvbmUgb2Yg4oCYY291bnRyaWVz4oCZLCDigJhtYXBfdW5pdHPigJksIOKAmHNvdmVyZWlnbnR54oCZLCDigJh0aW55X2NvdW50cmllc+KAmQoKLSAgIGNvbnRpbmVudDogYSBjaGFyYWN0ZXIgdmVjdG9yIG9mIGNvbnRpbmVudCBuYW1lcyB0byBnZXQgY291bnRyaWVzIGZyb20uCgotICAgY291bnRyeTogYSBjaGFyYWN0ZXIgdmVjdG9yIG9mIGNvdW50cnkgbmFtZXMuCgotICAgZ2VvdW5pdDogYSBjaGFyYWN0ZXIgdmVjdG9yIG9mIGdlb3VuaXQgbmFtZXMuCgotICAgc292ZXJlaWdudHk6IGEgY2hhcmFjdGVyIHZlY3RvciBvZiBzb3ZlcmVpZ250eSBuYW1lcy4KCi0gICByZXR1cm5jbGFzczog4oCYc3DigJkgZGVmYXVsdCBvciDigJhzZuKAmSBmb3IgU2ltcGxlIEZlYXR1cmVzCgpgYGB7cn0KbmVfY291bnRyaWVzKCkgJT4lIGdncGxvdCgpICsgZ2VvbV9zZigpCmBgYAoKYGBge3J9Cm5lX3dvcmxkIDwtIG5lX2NvdW50cmllcyhzY2FsZSA9ICJtZWRpdW0iLCByZXR1cm5jbGFzcyA9ICJzZiIpCmBgYAoKYGBge3J9CnN0cihuZV93b3JsZCkKYGBgCgpgYGB7cn0KbmVfd29ybGQgJT4lIGdncGxvdCgpICsgZ2VvbV9zZihhZXMoZmlsbCA9IHJlZ2lvbl93YikpCmBgYAoKYGBge3J9CmRmX2VkXzIwMjAgPC0gZGZfZWQgfD4gZmlsdGVyKHllYXIgPT0gMjAyMCkgfD4gc2VsZWN0KGlzbzJjLCBleHBlbmRpdHVyZSkKbmVfZWRfMjAyMCA8LSBuZV93b3JsZCB8PiBsZWZ0X2pvaW4oZGZfZWRfMjAyMCwgYnkgPSBjKCJ3Yl9hMiIgPSAiaXNvMmMiKSkKYGBgCgpgYGB7cn0KbmVfZWRfMjAyMCB8PiBnZ3Bsb3QoKSArIGdlb21fc2YoYWVzKGZpbGwgPSBleHBlbmRpdHVyZSkpCmBgYAoKYGBge3J9Cm5lX2VkXzIwMjAgfD4gZmlsdGVyKHN1YnJlZ2lvbiA9PSAiU291dGgtRWFzdGVybiBBc2lhIikgfD4gZ2dwbG90KCkgKyBnZW9tX3NmKGFlcyhmaWxsID0gZXhwZW5kaXR1cmUpKQpgYGAKCmBgYHtyfQpkZl9lZF8yMDIwIHw+IGRyb3BfbmEoZXhwZW5kaXR1cmUpIHw+IHB1bGwoKSB8PiByYW5nZSgpCmBgYAoKYGBge3J9CmRmX2VkXzIwMjAgfD4gZHJvcF9uYShleHBlbmRpdHVyZSkgfD4gZ2dwbG90KGFlcyhleHBlbmRpdHVyZSkpICsgZ2VvbV9oaXN0b2dyYW0oYmlud2lkdGggPSAzKSAKYGBgCgpJdCBpcyBwb3NzaWJsZSB0byB1c2UgcXVhbnRpbGUuCgpgYGB7cn0KZGZfZWRfMjAyMCB8PiBkcm9wX25hKGV4cGVuZGl0dXJlKSB8PiBwdWxsKGV4cGVuZGl0dXJlKSB8PiAKICBxdWFudGlsZShwcm9icyA9IGMoMC4yNSwwLjUsMC43NSwxKSkKYGBgCgpgYGB7cn0KbmVfZWRfMjAyMCB8PiBtdXRhdGUobGV2ZWwgPSBjdXQoZXhwZW5kaXR1cmUsIGJyZWFrcyA9IGMoMCwzLDYsOSwyMCksIGxhYmVscyA9IGMoIjAtMyIsIjMtNiIsIjYtOSIsIjktMTQiKSkpIHw+IGdncGxvdCgpICsgZ2VvbV9zZihhZXMoZmlsbCA9IGxldmVsKSkgKyBsYWJzKHRpdGxlID0gIkdvdmVybm1lbnQgZXhwZW5kaXR1cmUgb24gZWR1Y2F0aW9uLCB0b3RhbCAoJSBvZiBHRFApIGluIDIwMjAiKQpgYGAKCmBgYHtyfQpuZV9lZF8yMDIwIHw+IGZpbHRlcihjb250aW5lbnQgPT0gIkFmcmljYSIpIHw+IG11dGF0ZShsZXZlbCA9IGN1dChleHBlbmRpdHVyZSwgYnJlYWtzID0gYygwLDMsNiw5LDIwKSwgbGFiZWxzID0gYygiMC0zIiwiMy02IiwiNi05IiwiOS0xNCIpKSkgfD4gZ2dwbG90KCkgKyBnZW9tX3NmKGFlcyhmaWxsID0gbGV2ZWwpKSArIGxhYnModGl0bGUgPSAiR292ZXJubWVudCBleHBlbmRpdHVyZSBvbiBlZHVjYXRpb24sIFxudG90YWwgKCUgb2YgR0RQKSBpbiAyMDIwIikKYGBgCgojIEV4YW1wbGUKCiMjIFNjaG9vbCBFbnJvbGxtZW50IHZzIEdEUCBQZXIgQ2FwaXRhCgo+IFdlIHN0dWR5IHRoZSByZWxhdGlvbiBiZXR3ZWVuIHRoZSBzY2hvb2wgZW5yb2xsbWVudCBpbiBzZWNvbmRhcnkgYW5kIHRlcnRpYXJ5IGxldmVsIGFuZCB0aGUgZ2RwIHBlciBjYXBpdGEuCgojIyMgSW5kZXggU2VhcmNoCgpgYGB7cn0KV0RJc2VhcmNoKHN0cmluZyA9ICJzY2hvb2wgZW5yb2xsbWVudC4qKCUgZ3Jvc3MpIiwgZmllbGQgPSAibmFtZSIsIHNob3J0ID0gRkFMU0UpCmBgYAoKKipRIHRvIEFJOioqIFdoYXQgZG9lcyAnLlwqJyBtZWFuIGFzIGEgcmVndWxhciBleHByZXNzaW9uPwoKKipBIG9mIFtQb2VdKGh0dHBzOi8vcG9lLmNvbS8pIEFzc2lzdGFudDoqKiBJbiByZWd1bGFyIGV4cHJlc3Npb25zLCB0aGUgcGF0dGVybiAnLlwqJyBpcyBhIGNvbW1vbmx5IHVzZWQgZXhwcmVzc2lvbiB0aGF0IG1hdGNoZXMgYW55IHNlcXVlbmNlIG9mIGNoYXJhY3RlcnMgKGluY2x1ZGluZyBhbiBlbXB0eSBzZXF1ZW5jZSkuIEhlcmUncyB3aGF0IGl0IG1lYW5zOgoKLSAgIFRoZSBkb3QgJy4nIG1hdGNoZXMgYW55IHNpbmdsZSBjaGFyYWN0ZXIgZXhjZXB0IGEgbmV3bGluZS4KCi0gICBUaGUgYXN0ZXJpc2sgJ1wqJyBpcyBhIHF1YW50aWZpZXIgdGhhdCBtYXRjaGVzIHplcm8gb3IgbW9yZSBvY2N1cnJlbmNlcyBvZiB0aGUgcHJlY2VkaW5nIGVsZW1lbnQgKGluIHRoaXMgY2FzZSwgdGhlIGRvdCkuCgpUaGVyZWZvcmUsIHdoZW4gJy5cKicgaXMgdXNlZCBhcyBhIHJlZ3VsYXIgZXhwcmVzc2lvbiwgaXQgd2lsbCBtYXRjaCBhbnkgc2VxdWVuY2Ugb2YgY2hhcmFjdGVycywgcmVnYXJkbGVzcyBvZiBsZW5ndGggb3IgY29udGVudC4gSXQncyBhIHdheSB0byBleHByZXNzIGEgd2lsZGNhcmQgb3IgYSBjYXRjaC1hbGwgcGF0dGVybi4KCjEuICBTY2hvb2wgZW5yb2xsbWVudCwgc2Vjb25kYXJ5ICglIGdyb3NzKTogU0UuU0VDLkVOUlIKCi0gICBTY2hvb2wgZW5yb2xsbWVudCwgc2Vjb25kYXJ5ICglIGdyb3NzKSBHcm9zcyBlbnJvbGxtZW50IHJhdGlvIGlzIHRoZSByYXRpbyBvZiB0b3RhbCBlbnJvbGxtZW50LCByZWdhcmRsZXNzIG9mIGFnZSwgdG8gdGhlIHBvcHVsYXRpb24gb2YgdGhlIGFnZSBncm91cCB0aGF0IG9mZmljaWFsbHkgY29ycmVzcG9uZHMgdG8gdGhlIGxldmVsIG9mIGVkdWNhdGlvbiBzaG93bi4gU2Vjb25kYXJ5IGVkdWNhdGlvbiBjb21wbGV0ZXMgdGhlIHByb3Zpc2lvbiBvZiBiYXNpYyBlZHVjYXRpb24gdGhhdCBiZWdhbiBhdCB0aGUgcHJpbWFyeSBsZXZlbCwgYW5kIGFpbXMgYXQgbGF5aW5nIHRoZSBmb3VuZGF0aW9ucyBmb3IgbGlmZWxvbmcgbGVhcm5pbmcgYW5kIGh1bWFuIGRldmVsb3BtZW50LCBieSBvZmZlcmluZyBtb3JlIHN1YmplY3QtIG9yIHNraWxsLW9yaWVudGVkIGluc3RydWN0aW9uIHVzaW5nIG1vcmUgc3BlY2lhbGl6ZWQgdGVhY2hlcnMuCgoyLiAgU2Nob29sIGVucm9sbG1lbnQsIHRlcnRpYXJ5ICglIGdyb3NzKTogU0UuVEVSLkVOUlIKCi0gICBHcm9zcyBlbnJvbGxtZW50IHJhdGlvIGlzIHRoZSByYXRpbyBvZiB0b3RhbCBlbnJvbGxtZW50LCByZWdhcmRsZXNzIG9mIGFnZSwgdG8gdGhlIHBvcHVsYXRpb24gb2YgdGhlIGFnZSBncm91cCB0aGF0IG9mZmljaWFsbHkgY29ycmVzcG9uZHMgdG8gdGhlIGxldmVsIG9mIGVkdWNhdGlvbiBzaG93bi4gVGVydGlhcnkgZWR1Y2F0aW9uLCB3aGV0aGVyIG9yIG5vdCB0byBhbiBhZHZhbmNlZCByZXNlYXJjaCBxdWFsaWZpY2F0aW9uLCBub3JtYWxseSByZXF1aXJlcywgYXMgYSBtaW5pbXVtIGNvbmRpdGlvbiBvZiBhZG1pc3Npb24sIHRoZSBzdWNjZXNzZnVsIGNvbXBsZXRpb24gb2YgZWR1Y2F0aW9uIGF0IHRoZSBzZWNvbmRhcnkgbGV2ZWwuCgozLiAgR0RQIHBlciBjYXBpdGEsIFBQUCAoY29uc3RhbnQgMjAxNyBpbnRlcm5hdGlvbmFsIFwkKTogTlkuR0RQLlBDQVAuUFAuS0QKCi0gICBHRFAgcGVyIGNhcGl0YSwgUFBQIChjb25zdGFudCAyMDE3IGludGVybmF0aW9uYWwgXCQpIEdEUCBwZXIgY2FwaXRhIGJhc2VkIG9uIHB1cmNoYXNpbmcgcG93ZXIgcGFyaXR5IChQUFApLiBQUFAgR0RQIGlzIGdyb3NzIGRvbWVzdGljIHByb2R1Y3QgY29udmVydGVkIHRvIGludGVybmF0aW9uYWwgZG9sbGFycyB1c2luZyBwdXJjaGFzaW5nIHBvd2VyIHBhcml0eSByYXRlcy4gQW4gaW50ZXJuYXRpb25hbCBkb2xsYXIgaGFzIHRoZSBzYW1lIHB1cmNoYXNpbmcgcG93ZXIgb3ZlciBHRFAgYXMgdGhlIFUuUy4gZG9sbGFyIGhhcyBpbiB0aGUgVW5pdGVkIFN0YXRlcy4gR0RQIGF0IHB1cmNoYXNlcidzIHByaWNlcyBpcyB0aGUgc3VtIG9mIGdyb3NzIHZhbHVlIGFkZGVkIGJ5IGFsbCByZXNpZGVudCBwcm9kdWNlcnMgaW4gdGhlIGNvdW50cnkgcGx1cyBhbnkgcHJvZHVjdCB0YXhlcyBhbmQgbWludXMgYW55IHN1YnNpZGllcyBub3QgaW5jbHVkZWQgaW4gdGhlIHZhbHVlIG9mIHRoZSBwcm9kdWN0cy4gSXQgaXMgY2FsY3VsYXRlZCB3aXRob3V0IG1ha2luZyBkZWR1Y3Rpb25zIGZvciBkZXByZWNpYXRpb24gb2YgZmFicmljYXRlZCBhc3NldHMgb3IgZm9yIGRlcGxldGlvbiBhbmQgZGVncmFkYXRpb24gb2YgbmF0dXJhbCByZXNvdXJjZXMuIERhdGEgYXJlIGluIGNvbnN0YW50IDIwMTcgaW50ZXJuYXRpb25hbCBkb2xsYXJzLgoKIyMjIEltcG9ydGluZyBEYXRhCgpgYGB7ciBldmFsPUZBTFNFfQpkZl9zZWNfdGVyX2dkcCA8LSBXREkoCiAgaW5kaWNhdG9yID0gYyhzZWNvbmRhcnkgPSAiU0UuU0VDLkVOUlIiLCB0ZXJ0aWFyeSA9ICJTRS5URVIuRU5SUiIsIAogICAgICAgICAgICAgICAgZ2RwcGNhcCA9ICJOWS5HRFAuUENBUC5QUC5LRCIpLCAKICBleHRyYSA9IFRSVUUsIGNhY2hlID0gd2RpY2FjaGUpCmBgYAoKYGBge3IgZXZhbD1GQUxTRX0Kd3JpdGVfY3N2KGRmX3NlY190ZXJfZ2RwLCAiZGF0YS9zZWNfdGVyX2dkcC5jc3YiKQpgYGAKCmBgYHtyfQpkZl9kZl9zZWNfdGVyX2dkcCA8LSByZWFkX2NzdigiZGF0YS9zZWNfdGVyX2dkcC5jc3YiKQpgYGAKCiMjIyBWaWV3aW5nIHRoZSBkYXRhCgpgYGB7cn0KZGZfc2VjX3Rlcl9nZHAKYGBgCgpgYGB7cn0KZGZfc2VjX3Rlcl9nZHAgfD4gc3RyKCkKYGBgCgojIyMgQ3JlYXRpbmcgYSBMb25nIFRhYmxlCgpgYGB7cn0KZGZfc2VjX3Rlcl9nZHBfbG9uZyA8LSBkZl9zZWNfdGVyX2dkcCB8PiAKICBwaXZvdF9sb25nZXIoY29scyA9IGMoc2Vjb25kYXJ5LCB0ZXJ0aWFyeSkpIHw+CiAgc2VsZWN0KGNvdW50cnksIGlzbzJjLCB5ZWFyLCBnZHBwY2FwLCBuYW1lLCB2YWx1ZSwgcmVnaW9uLCBpbmNvbWUpCmRmX3NlY190ZXJfZ2RwX2xvbmcKYGBgCgojIyMgVmlzdWFsaXppbmcgYnkgTGluZSBHcmFwaHMKCmBgYHtyfQpDT1VOVFJZIDwtICJXb3JsZCIKZGZfc2VjX3Rlcl9nZHBfbG9uZyB8PiBmaWx0ZXIoY291bnRyeSA9PSBDT1VOVFJZKSB8PiBkcm9wX25hKHZhbHVlKSB8PgogIGdncGxvdCgpICsgZ2VvbV9saW5lKGFlcyh5ZWFyLCB2YWx1ZSwgY29sID0gbmFtZSkpCiAgbGFicyh0aXRsZSA9ICJTY2hvb2wgZW5yb2xsbWVudDsgU2Vjb25kYXJ5IGFuZCBUZXJ0aWFyeSIpCmBgYAoKT2JzZXJ2YXRpb25zOgoKLSAgIFRoZSBlbnJvbGxtZW50cyBvZiBib3RoIGxldmVscyBhcmUgaW5jcmVhc2luZyByYXBpZGx5IGFmdGVyIDE5OTAuCgpgYGB7cn0KSU5DT01FIDwtIGMoIkhpZ2ggaW5jb21lIiwgIlVwcGVyIG1pZGRsZSBpbmNvbWUiLCJNaWRkbGUgaW5jb21lIiwiTG93ZXIgbWlkZGxlIGluY29tZSIsIkxvdyAmIG1pZGRsZSBpbmNvbWUiLCAiTG93IGluY29tZSIpCmRmX3NlY190ZXJfZ2RwX2xvbmcgfD4gZmlsdGVyKGNvdW50cnkgJWluJSBJTkNPTUUpIHw+IGRyb3BfbmEodmFsdWUpIHw+CiAgZ2dwbG90KGFlcyh5ZWFyLCB2YWx1ZSwgY29sID0gZmFjdG9yKGNvdW50cnksIGxldmVscyA9IElOQ09NRSksIGxpbmV0eXBlID0gbmFtZSkpICsgZ2VvbV9saW5lKCkgKyB5bGltKGMoMCwxMTApKSArCiAgbGFicyh0aXRsZSA9ICJTY2hvb2wgZW5yb2xsbWVudDogU2Vjb25kYXJ5IGFuZCBUZXJ0aWFyeSIsIAogICAgICAgY29sID0gIkluY29tIExldmVscyIsCiAgICAgICBsaW5ldHlwZSA9ICJTY2hvb2wgTGV2ZWxzIiwgeSA9ICIiKQpgYGAKCioqT2JzZXJ2YXRpb25zKioKCi0gICBJbiB0aGlzIGNlbnR1cnksIHdlIGNhbiBvYnNlcnZlIGltcHJvdmVtZW50cyBpbiBlbnJvbGxtZW50cy4gTmVlZCB0byBzdHVkeSBtb3JlIGluIGRldGFpbC4KCiMjIyBTY2F0dGVycGxvdHMgZm9yIENvdmFyaWF0aW9uCgpgYGB7cn0KZGZfc2VjX3Rlcl9nZHBfbG9uZyB8PiBmaWx0ZXIoeWVhciA9PSAyMDIwKSB8PiBkcm9wX25hKHZhbHVlLCBnZHBwY2FwKSB8PgogIGdncGxvdChhZXMoZ2RwcGNhcCwgdmFsdWUsIGNvbCA9IG5hbWUpKSArIGdlb21fcG9pbnQoKSArIAogIGxhYnModGl0bGUgPSAiU2Nob29sIGVucm9sbG1lbnQ6IFNlY29uZGFyeSBhbmQgVGVydGlhcnkgdnMgR0RQIHBlciBjYXBpdGEiLCB5ID0gIiIpCmBgYAoKKipPYnNlcnZhdGlvbnMqKgoKLSAgIE5lZWQgdG8gdHJ5IGxvZzEwIGNvbnZlcnRpb24gb2YgZ2RwcGNhcCBhcyBtYW55IHBvaW50cyBhcmUgbmVhciB0aGUgb3JpZ2luLgoKYGBge3J9CmRmX3NlY190ZXJfZ2RwX2xvbmcgfD4gZmlsdGVyKHllYXIgPT0gMjAyMCkgfD4gZHJvcF9uYSh2YWx1ZSwgZ2RwcGNhcCkgfD4KICBnZ3Bsb3QoYWVzKGdkcHBjYXAsIHZhbHVlLCBjb2wgPSBuYW1lKSkgKyBnZW9tX3BvaW50KCkgKyAKICBzY2FsZV94X2xvZzEwKCkgKwogIGxhYnModGl0bGUgPSAiU2Nob29sIGVucm9sbG1lbnQ7IFNlY29uZGFyeSBhbmQgVGVydGlhcnkgdnMgR0RQIHBlciBjYXBpdGEgaW4gbG9nMTAgc2NhbGUiLCB5ID0gIiIpCmBgYAoKYGBge3J9CmRmX3NlY190ZXJfZ2RwX2xvbmcgfD4gZmlsdGVyKHllYXIgPT0gMjAyMCkgfD4gZHJvcF9uYSh2YWx1ZSwgZ2RwcGNhcCkgfD4KICBnZ3Bsb3QoYWVzKGdkcHBjYXAsIHZhbHVlLCBjb2wgPSBuYW1lKSkgKyBnZW9tX3BvaW50KCkgKyAKICBnZW9tX3Ntb290aChtZXRob2QgPSAibG0iLCBzZSA9IEZBTFNFLCBmb3JtdWxhID0gJ3l+eCcpICsKICBzY2FsZV94X2xvZzEwKCkgKwogIGxhYnModGl0bGUgPSAiU2Nob29sIGVucm9sbG1lbnQ7IFNlY29uZGFyeSBhbmQgVGVydGlhcnkgdnMgR0RQIHBlciBjYXBpdGEgaW4gbG9nMTAgc2NhbGUiLCB5ID0gIiIpCmBgYAoKYGBge3J9CmRmX3NlY190ZXJfZ2RwX2xvbmcgfD4gZmlsdGVyKHllYXIgPT0gMjAyMCkgfD4gZHJvcF9uYShnZHBwY2FwLCB2YWx1ZSkgfD4KICBmaWx0ZXIobmFtZSA9PSAic2Vjb25kYXJ5IikgfD4gCiAgbG0odmFsdWV+bG9nMTAoZ2RwcGNhcCksIGRhdGEgPSBfKSB8PiBzdW1tYXJ5KCkKYGBgCgpgYGB7cn0KZGZfc2VjX3Rlcl9nZHBfbG9uZyB8PiBmaWx0ZXIoeWVhciA9PSAyMDIwKSB8PiBkcm9wX25hKGdkcHBjYXAsIHZhbHVlKSB8PgogIGZpbHRlcihuYW1lID09ICJ0ZXJ0aWFyeSIpIHw+IAogIGxtKHZhbHVlfmxvZzEwKGdkcHBjYXApLCBkYXRhID0gXykgfD4gc3VtbWFyeSgpCmBgYAoKKipPYnNlcnZhdGlvbnMqKgoKLSAgIEJvdGggc2Vjb25kYXJ5IGFuZCB0ZXJ0aWFyeSBsZXZlbCwgdGhlIGVucm9sbG1lbnQgY29ycmVsYXRlIHdpdGggdGhlIGxvZzEwIHZhbHVlcyBvZiBnZHAgcGVyIGNhcGl0YS4KCiMjIyBCb3ggUGxvdHMgCgpgYGB7cn0KZGZfc2VjX3Rlcl9nZHBfbG9uZyB8PiBmaWx0ZXIoeWVhciA9PSAyMDIwLCByZWdpb24gIT0gIkFnZ3JlZ2F0ZXMiKSB8PiBkcm9wX25hKHZhbHVlLCByZWdpb24pIHw+CiAgZ2dwbG90KGFlcyhuYW1lLCB2YWx1ZSwgZmlsbCA9IHJlZ2lvbikpICsgZ2VvbV9ib3hwbG90KCkgKyAKICBsYWJzKHRpdGxlID0gIlNlY29uZGFyeSBhbmQgdGVydGlhcnkgc2Nob29sIGVucm9sbG1lbnQgYnkgcmVnaW9uIiwgeSA9ICJTY2hvb2wgZW5yb2xsbWVudCAoJSBncm9zcykiLCB4ID0gIiIsIGZpbGwgPSAiIikgKyAKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAidG9wIikKYGBgCgoqKk9ic2VydmF0aW9ucyoqCgotICAgUmVnaW9uYWwgZGlmZmVyZW5jZXMgYXJlIGxhcmdlIGluIHRlcnRpYXJ5IGxldmVsLgoKYGBge3J9CmRmX3NlY190ZXJfZ2RwX2xvbmcgfD4gZmlsdGVyKHllYXIgPT0gMjAyMCwgcmVnaW9uICE9ICJBZ2dyZWdhdGVzIikgfD4gZHJvcF9uYSh2YWx1ZSwgaW5jb21lKSB8PgogIGdncGxvdChhZXMobmFtZSwgdmFsdWUsIGZpbGwgPSBmYWN0b3IoaW5jb21lLCBsZXZlbHMgPSBJTkNPTUUpKSkgKyBnZW9tX2JveHBsb3QoKSArIAogIGxhYnModGl0bGUgPSAiU2Vjb25kYXJ5IGFuZCB0ZXJ0aWFyeSBzY2hvb2wgZW5yb2xsbWVudCBieSBpbmNvbWUgbGV2ZWwiLCB5ID0gIlNjaG9vbCBlbnJvbGxtZW50ICglIGdyb3NzKSIsIHggPSAiIiwgZmlsbCA9ICIiKSArIAogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJ0b3AiKQpgYGAKCioqT2JzZXJ2YXRpb25zKioKCi0gICBJbmNvbWUgbGV2ZWwgaGFzIG1vcmUgZWZmZWN0IG9uIHNjaG9vbCBlbnJvbGxtZW50IHRvIGJvdGggc2Vjb25kYXJ5IGFuZCB0ZXJ0aWFyeSBlZHVjYXRpb24KCgoKIyBZb3VyIFByb2plY3QKCiMjIFRpdGxlIG9mIHlvdXIgcHJvamVjdAoKKlRoZSB0aXRsZSBjYW4gYmUgaW4gdGhlIHRpdGxlIGluIFlBTUwuKgoKIyMjIFNob3J0IEFic3RyYWN0CgpXZSBzdHVkeSAuLi4uLgoKIyMjIEFib3V0IERhdGEKCjEuICBOYW1lIG9mIHRoZSBpbmRpY2F0b3IgMTogSW5kaWNhdG9yIENvZGUgMQoKLSAgIERlc2NyaXB0aW9uOgoKMi4gIE5hbWUgb2YgdGhlIGluZGljYXRvciAyOiBJbmRpY2F0b3IgQ29kZSAyCgotICAgRGVzY3JpcHRpb246CgozLiAgLi4uCgojIyMgU2V0IHVwCgpgYGB7cn0KbGlicmFyeSh0aWR5dmVyc2UpCmxpYnJhcnkoV0RJKQpgYGAKCipDcmVhdGUgZGF0YSBmb2xkZXIgaWYgeW91IGRvIG5vdCBoYXZlIGl0IHVuZGVyIEZpbGVzLioKCmBgYHtyIGV2YWw9RkFMU0V9CmRpci5jcmVhdGUoImRhdGEiKQpgYGAKCipJZiB5b3UgZG8gbm90IGhhdmUgYHdkaWNhY2hlLnJkc2AgaW4geW91ciBkYXRhIGZvbGRlciwgcnVuIHRoZSBmb2xsb3dpbmcgdHdvIGNvZGUgY2h1bmtzLioKCmBgYHtyIHdkaWNhY2hlLCBldmFsPUZBTFNFfQp3ZGljYWNoZSA8LSBXREljYWNoZSgpCmBgYAoKYGBge3Igd3JpdGV3ZGljYWNoZSwgZXZhbD1GQUxTRSwgZWNobz1GQUxTRX0Kd3JpdGVfcmRzKHdkaWNhY2hlLCAiZGF0YS93ZGljYWNoZS5yZHMiKQpgYGAKCmBgYHtyIHJlYWR3ZGljYWNoZSwgZWNobz1GQUxTRX0Kd2RpY2FjaGUgPC0gcmVhZF9yZHMoImRhdGEvd2RpY2FjaGUucmRzIikKYGBgCgojIyMgSW1wb3J0aW5nIERhdGEKCkVkaXQgc2hvcnRfbmFtZV8xLCBjaG9zZW5faW5kaWNhdG9yXzEsIHNob3J0X25hbWVfMiwgY2hvc2VuX2luZGljYXRvcl8yLCBldGMuIFlvdSBjYW4gZWRpdCBgZGZfeW91cmRhdGFgIHRvIGEgZGVzY3JpcHRpdmUgbmFtZS4gSWYgeW91IGVkaXQgYGRmX3lvdXJkYXRhYCAsIHBsZWFzZSBlZGl0IG90aGVyIHBhcnRzIGFzIHdlbGwuCgpgYGB7cn0KZGZfeW91cmRhdGEgPC0gV0RJKAogIGluZGljYXRvciA9IGMoc2hvcnRfbmFtZV8xID0gY2hvc2VuX2luZGljYXRvcl8xLAogICAgICAgICAgICAgICAgc2hvcnRfbmFtZV8yID0gY2hvc2VuX2luZGljYXRvcl8yKSwKICBleHRyYSA9IFRSVUUsIGNhY2hlID0gd2RpY2FjaGUpCmBgYAoKYGBge3J9CndyaXRlX2NzdihkZl95b3VyZGF0YSwgImRhdGEveW91cmRhdGEuY3N2IikKYGBgCgpgYGB7cn0KZGZfeW91cmRhdGEgPC0gcmVhZF9jc3YoImRhdGEveW91cmRhdGEuY3N2IikKYGBgCgojIyMgVmlld2luZyBkYXRhCgpgYGB7cn0KCmBgYAoKYGBge3J9CgpgYGAKCiMjIyBDcmVhdGluZyBhIGxvbmcgdGFibGUKCiMjIyMgRXhhbXBsZS4KCmBgYApkZl9zZWNfdGVyX2dkcF9sb25nIDwtIGRmX3NlY190ZXJfZ2RwIHw+IAogIHBpdm90X2xvbmdlcihjb2xzID0gYyhzZWNvbmRhcnksIHRlcnRpYXJ5KSkgCmRmX3NlY190ZXJfZ2RwX2xvbmcKYGBgCgoKYGBge3J9CgpgYGAKCiMjIyBWaXN1YWxpemluZyBkYXRhCgpgYGB7cn0KCmBgYAoKKipPYnNlcnZhdGlvbnMgYW5kIFF1ZXN0aW9uczoqKgoKLSAKCgpgYGB7cn0KCmBgYAoKKipPYnNlcnZhdGlvbnMgYW5kIFF1ZXN0aW9uczoqKgoKLSAgIAoKYGBge3J9CgpgYGAKCioqT2JzZXJ2YXRpb25zIGFuZCBRdWVzdGlvbnM6KioKCi0gIAoKCiMjIyBBIGNob3JvcGxldGggbWFwCgpJZiBwb3NzaWJsZSwgY3JlYXRlIGEgY2hvcm9wbGV0aCBtYXAuIChhIGNoYWxsZW5nZSwgbm90IHJlcXVpcmVkKQoKYGBge3J9CgpgYGAKCioqT2JzZXJ2YXRpb25zIGFuZCBRdWVzdGlvbnM6KioKCi0gIAoKLSAK